﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Harkon.AppServer.cOne.Service;
using System.Threading;
using System.Collections;

namespace Harkon.AppServer.cOne.Events
{
    public class EventManager : AbstractService, IEventManager
    {

        private IDictionary<string, IList<EventConsumerDelegate>> registeredDelegates = new Dictionary<string, IList<EventConsumerDelegate>>();
        private Queue<TopicParamPair> incomingQueue = new Queue<TopicParamPair>();

        public void Subscribe(string topic, EventConsumerDelegate targetDelegate)
        {
            if (!registeredDelegates.ContainsKey(topic))
                registeredDelegates.Add(topic, new List<EventConsumerDelegate>());
            registeredDelegates[topic].Add(targetDelegate);
        }

        public void Publish(string topic, string eventParameter)
        {
            //insert into queue
            lock (incomingQueue)
            {
                incomingQueue.Enqueue(new TopicParamPair { Topic = topic, Param = eventParameter });
            }
            //wake the thread
            lock (this)
            {
                Monitor.Pulse(this);
            }
        }

        #region lifecycle

        private bool running = false;
        private Thread publisher = null;

        public override bool Init()
        {
            if (base.Init())
            {
                publisher = new Thread(Run);
                publisher.Name = "EventManager";
                publisher.IsBackground = true;
                return true;
            }
            return false;
        }

        public override bool Start()
        {
            if (base.Start())
            {
                running = true;
                publisher.Start();
                return true;
            }
            return false;
        }

        public override bool Stop()
        {
            if (base.Stop())
            {
                running = false;
                lock (this)
                {
                    Monitor.Pulse(this);
                }
                return true;
            }
            return false;
        }

        private void Run()
        {
            while (running)
            {
                int entriesCount = 0;
                lock (incomingQueue)
                {
                    entriesCount = incomingQueue.Count;
                }

                if (entriesCount == 0)
                {
                    lock (this)
                    {
                        Monitor.Wait(this, 1000);
                    }
                }
                else
                {
                    lock (incomingQueue)
                    {
                        var latestEntry = incomingQueue.Dequeue();
                        if (registeredDelegates.ContainsKey(latestEntry.Topic))
                        {
                            foreach (var specialDelegate in registeredDelegates[latestEntry.Topic])
                            {
                                specialDelegate(latestEntry.Param);
                            }
                        }
                    }
                }
            }
        }

        #endregion
    }
}

class TopicParamPair
{
    public string Topic { get; set; }
    public string Param { get; set; }
}